import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Scanner;

public class LSB {
    //图片宽高
    private static int imgHight = 1;
    private static int imgWidth = 1;
    private static int imgHight2= 1;
    private static int imgWidth2 = 1;
    //像素矩阵集合
    private static ArrayList<String[][]> resList = new ArrayList<>();
    //原像素矩阵
    public static void main(String[] args) throws IOException {
        Scanner scanner = new Scanner(System.in);
        System.out.println("所需要加密的图像路径：");
        String str1 = scanner.nextLine();
        System.out.println("伪装图像路径");
        String str2 = scanner.nextLine();
        //加密
        encryption(str2,str1);
        //解密
        Decrypt(str1);


    }

    /**
     * 初始化并加密
     * @param src 载体图像路径
     * @param src2 秘密图像路径
     * @throws IOException
     */
    public static void encryption(String src, String src2) throws IOException {

        System.out.println("载体图像路径："+src+" 秘密图像路径："+src2);
        System.out.println("开始加密....");

        //图像操纵对象
        BufferedImage imgSrc = ImageIO.read(new File(src));
        BufferedImage imgSrc2 = ImageIO.read(new File(src2));
        //图片类型
        int imgType = 5;
        imgHight = imgSrc.getHeight();
        imgWidth = imgSrc.getWidth();
        imgHight2 = imgSrc2.getHeight();
        imgWidth2 = imgSrc2.getWidth();

        //创建存储像素信息的三个矩阵
        resList.clear();
        resList.add(ru(imgWidth,imgHight));
        resList.add(ru(imgWidth2,imgHight2));
        resList.add(ru(imgWidth,imgHight));

        //记录载体图像像素信息到第一个矩阵里
        for (int i = 0; i < imgWidth; i++) {
            for (int j = 0; j < imgHight; j++) {
                resList.get(0)[i][j] = Integer.toBinaryString(imgSrc.getRGB(i, j));
            }
        }
        //记录秘密图像像素信息到第二个矩阵里
        for (int i = 0; i < imgWidth2; i++) {
            for (int j = 0; j < imgHight2; j++) {
                resList.get(1)[i][j] = Integer.toBinaryString(imgSrc2.getRGB(i, j));
            }
        }
        //默认从左上角开始隐藏
        for (int i = 0; i < imgWidth; i++) {
            //如果小于隐藏图像的宽度，列号
            if (i<imgWidth2){
                for (int j = 0; j < imgHight; j++) {
                    //且小于隐藏图像的高度，行号
                    //则为秘密图像的宽高范围，应发生置换
                    if (j<imgHight2){
                        char[] chars1 = resList.get(0)[i][j].toCharArray();
                        char[] chars3 = chars1;
                        char[] chars2 = resList.get(1)[i][j].toCharArray();
                        //就将对应的位置信息放置在对应像素的透明度、红、绿、蓝通道的低4bit位
                        //采用U型替换规则，加密顺时针替换，解密逆时针替换

                        //蓝通道
                        chars3[31] = chars2[24];
                        chars3[30] = chars2[25];
                        chars3[29] = chars2[26];
                        chars3[28] = chars2[27];
                        //绿通道
                        chars3[23] = chars2[16];
                        chars3[22] = chars2[17];
                        chars3[21] = chars2[18];
                        chars3[20] = chars2[19];
                        //红通道
                        chars3[15] = chars2[8];
                        chars3[14] = chars2[9];
                        chars3[13] = chars2[10];
                        chars3[12] = chars2[11];
                        //透明度通道
                        chars3[7] = chars2[0];
                        chars3[6] = chars2[1];
                        chars3[5] = chars2[2];
                        chars3[4] = chars2[3];
                        //保存置换后的像素信息至第三个矩阵中
                        resList.get(2)[i][j] = String.valueOf(chars3);
                    }else {
                        //保存没有置换的像素信息至第三个矩阵中
                        resList.get(2)[i][j] = String.valueOf(resList.get(0)[i][j].toCharArray());
                    }
                }
            }else {
                for (int j = 0; j < imgHight; j++) {
                    resList.get(2)[i][j] = String.valueOf(resList.get(0)[i][j].toCharArray());
                }
            }
        }


        //输出加密结果
        oimg(resList.get(2),"已伪装图像",imgWidth,imgHight);


        System.out.println("加密完成....");
    }

    public static void Decrypt(String src) throws IOException {
        //图像操纵对象
        BufferedImage imgSrc = ImageIO.read(new File(src));
        //图片类型
        int imgType = 5;
        imgWidth = imgSrc.getWidth();
        imgHight = imgSrc.getHeight();
        System.out.println(imgWidth2);
        System.out.println(imgHight2);

        resList.clear();
        resList.add(ru(imgWidth,imgHight));
        resList.add(ru(imgWidth2,imgHight2));

        for (int i = 0; i < imgWidth; i++) {
            if (i<imgWidth2){
                for (int j = 0; j < imgHight; j++) {
                    if (j<imgHight2){
                        char[] chars1 = Integer.toBinaryString(imgSrc.getRGB(i, j)).toCharArray();

                        char[] chars2 = new char[32];
                        char[] chars3 = new char[32];
                        for (int h = 0; h < 32; h++){
                            chars2[h] = '0';
                            chars3[h] = '0';
                        }
                        chars2[24] = chars1[24];
                        chars2[25] = chars1[25];
                        chars2[26] = chars1[26];
                        chars2[27] = chars1[27];
                        chars3[24] = chars1[31];
                        chars3[25] = chars1[30];
                        chars3[26] = chars1[29];
                        chars3[27] = chars1[28];

                        chars2[16] = chars1[16];
                        chars2[17] = chars1[17];
                        chars2[18] = chars1[18];
                        chars2[19] = chars1[19];
                        chars3[16] = chars1[23];
                        chars3[17] = chars1[22];
                        chars3[18] = chars1[21];
                        chars3[19] = chars1[20];

                        chars2[8] = chars1[8];
                        chars2[9] = chars1[9];
                        chars2[10] = chars1[10];
                        chars2[11] = chars1[11];
                        chars3[8] = chars1[15];
                        chars3[9] = chars1[14];
                        chars3[10] = chars1[13];
                        chars3[11] = chars1[12];

                        chars2[0] = chars1[0];
                        chars2[1] = chars1[1];
                        chars2[2] = chars1[2];
                        chars2[3] = chars1[3];
                        chars3[0] = chars1[7];
                        chars3[1] = chars1[6];
                        chars3[2] = chars1[5];
                        chars3[3] = chars1[4];
                        resList.get(0)[i][j] = String.valueOf(chars2);
                        resList.get(1)[i][j] = String.valueOf(chars3);
                    }else {
                        resList.get(0)[i][j] = Integer.toBinaryString(imgSrc.getRGB(i, j));
                    }
                }
            }else {
                for (int j = 0; j < imgHight; j++) {
                    resList.get(0)[i][j] = Integer.toBinaryString(imgSrc.getRGB(i, j));
                }
            }

        }

        oimg(resList.get(0),"解密后载体图像",imgWidth,imgHight);
        oimg(resList.get(1),"解密后秘密图像",imgWidth2,imgHight2);

        System.out.println("解密完成....");
    }

    /**
     * 生产像素矩阵
     * @param width
     * @param hight
     * @return
     */
    public static String[][] ru(int width,int hight){
        return new String[width][hight];
    }

    /**
     * 图片输出方法
     * @param matrix
     * @param name
     * @param imgWidth
     * @param imgHight
     */
    public static void oimg(String[][] matrix, String name,int imgWidth, int imgHight){
        BufferedImage imgRes = new BufferedImage(imgWidth, imgHight, 5);
        for (int i = 0; i < imgWidth; i++) {
            for (int j = 0; j < imgHight; j++) {
//                System.out.println("第"+name+"个  i:"+i+"  j:"+j+"  值："+Integer.parseUnsignedInt(r[i][j],2));
                imgRes.setRGB(i,j,Integer.parseUnsignedInt(matrix[i][j],2));
            }
        }
        File imgOut = new File("D:/java"+name+".jpg");
        //输出文件
        try {
            ImageIO.write(imgRes, "jpg", imgOut);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}





